package com.zyy.joseata.interceptor.datasource;

import com.zyy.joseata.advice.MethodAdvice;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.Advisor;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator;
import org.springframework.aop.support.DefaultIntroductionAdvisor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.NameMatchMethodPointcut;
import org.springframework.beans.BeansException;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.lang.reflect.Method;

@Component
@Slf4j
public class JoSeataAutoDataSourceProxyCreator extends AbstractAutoProxyCreator {

    @Resource
    private MethodAdvice methodAdvice;

    /**
     * 用于返回哪些类使用哪个代理类.
     * @param aClass
     * @param s
     * @param targetSource
     * @return
     * @throws BeansException
     */
    @Override
    protected Object[] getAdvicesAndAdvisorsForBean(Class<?> aClass, String s, TargetSource targetSource) throws BeansException {
        // 该方法是类遍历的时候执行, 遍历一个类执行一次
        if(shouldSkip(aClass,aClass.getName())){
            return DO_NOT_PROXY;
        }
        log.info("对datasource进行了加强.....");
        Advisor advisor = new DefaultIntroductionAdvisor(new JoSeataAutoDataSourceProxyAdvice());
        return new Object[]{advisor};
    }

    @Override
    protected boolean shouldSkip(Class<?> beanClass, String beanName){
        return !DataSource.class.isAssignableFrom(beanClass);
    }

    //@Override
    protected Object[] getAdvicesAndAdvisorsForBean_method_ok(Class<?> beanClass, String beanName, TargetSource customTargetSource) {

        if(isInfrastructureClass(beanClass) || shouldSkip(beanClass,beanName)){
            return DO_NOT_PROXY;
        }

        DefaultPointcutAdvisor genericMethodAdvisor = new DefaultPointcutAdvisor();
        NameMatchMethodPointcut genericMethodPointcut = new NameMatchMethodPointcut();
        // 要被加强的方法名
        genericMethodPointcut.addMethodName("get");
        genericMethodAdvisor.setPointcut(genericMethodPointcut);
        genericMethodAdvisor.setAdvice(new MethodBeforeAdvice() {
            @Override
            public void before(Method method, Object[] objects, Object o) throws Throwable {
                methodAdvice.beforeAdvice();
            }
        });

        DefaultPointcutAdvisor specificMethodAdvisor = new DefaultPointcutAdvisor();
        NameMatchMethodPointcut specialMethodPointcut = new NameMatchMethodPointcut();

        // 要被加强的方法名
        specialMethodPointcut.addMethodName("getSystem");
        specificMethodAdvisor.setPointcut(specialMethodPointcut);
        specificMethodAdvisor.setAdvice(new MethodBeforeAdvice() {
            @Override
            public void before(Method method, Object[] objects, Object o) throws Throwable {
                methodAdvice.specificBeforeAdvice();
            }
        });
        return new Object[]{genericMethodAdvisor, specificMethodAdvisor};
    }

}
